package com.tangsm.spring.boot.springdoc.handler;

import com.tangsm.spring.boot.springdoc.exception.BusinessException;
import com.tangsm.spring.boot.springdoc.domain.base.Result;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局统一异常处理
 *
 * <p>该类中的设计思路：</p>
 * <p>1. 使用@ExceptionHandler注解捕获指定或自定义的异常；</p>
 * <p>2. 使用@ControllerAdvice或@RestControllerAdvice配置成全局处理类；（这个根据你想要返回的类型来决定，返回Json格式使用@RestControllerAdvice）</p>
 * <p>3. 必须定义一个通用的异常捕获方法，便于捕获未定义的异常信息；</p>
 * <p>4. 自定一个异常类，捕获针对项目或业务的异常;</p>
 * <p>5. 异常的对象信息补充到统一结果枚举中；</p>
 *
 * @author tangsm
 * @date 2021-07-27
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 400系统异常统一处理
     *
     * @param ex 异常对象
     * @return 通用返回参数
     */
    @ExceptionHandler(ConversionFailedException.class)
    public Result<String> handleConnversion(RuntimeException ex) {
        Result<String> result = Result.failed();
        result.setCode(HttpStatus.BAD_REQUEST.value());
        result.setMessage(ex.getMessage());
        return result;
    }

    /**
     * 系统自定义业务异常统一处理
     *
     * @param ex 异常对象
     * @return 通用返回参数
     */
    @ExceptionHandler(BusinessException.class)
    public Result<String> handleBookNotFound(BusinessException ex) {
        ex.printStackTrace();

        Result<String> result = Result.failed();
        result.setCode(ex.getCode());
        result.setMessage(ex.getMessage());
        return result;
    }

    /**
     * 参数验证失败异常
     *
     * @param ex 异常对象
     * @return 通用返回参数
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleNotValid(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();

        StringBuilder stringBuilder = new StringBuilder();
        for (FieldError error : bindingResult.getFieldErrors()) {
            String field = error.getField();
            Object value = error.getRejectedValue();
            String msg = error.getDefaultMessage();
            String message = String.format("错误字段：%s，错误值：%s，原因：%s；", field, value, msg);
            stringBuilder.append(message).append("\r\n");
        }

        Result<String> result = Result.failed();
        result.setCode(400);
        result.setMessage(stringBuilder.toString());
        return result;
    }

    /**
     * 500系统异常统一处理
     *
     * @param ex 异常对象
     * @return 通用返回参数
     */
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception ex) {
        ex.printStackTrace();

        Result<String> result = Result.failed();
        result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
        result.setMessage(ex.getMessage());
        return result;
    }
}
